#!/usr/bin/env python
# encoding: utf-8
'''
@author: guihehans
@file: gittag_extract.py
@time: 2020/4/3 11:21
@function:

'''
import sys

from jenkins_tool.common.SYSDBUtils import Mysql_DB
from jenkins_tool.log import Logger
from jenkins_tool.common import const, sql_mapping, EnhanceUtills
import re
import pandas as pd

from jenkins_tool.service import jenkins_api

module_name = "gittag_extract"
system_id = const.SYS_ID
global logger
logger = Logger.Logger(clevel=const.Logging_command_level, Flevel=const.Logging_file_level)


def get_info_from_db(schema: str, task_id: int, sql_mapper: str):
    """
    get data from mysql database
    :param schema:parse db schema. eg：redmine
    :param task_id:parse the task id
    :param sql_mapper: the hash_map key to get the sql str in sql_mapping.
    :return:return query result in pandas DataFrame.
    """
    sql_str = sql_mapping.SQL_MAPPING[sql_mapper]
    param_value = [task_id]
    # print(sql_str,param_value,schema)
    df = Mysql_DB(schema).do_sql_query(sql_str, param_value)
    return df


def get_status_from_redmine(task_id, schema="redmine"):
    """
    get the status from redmine db. 
    :param task_id: int eg.26771
    :param schema: fixed to 'get_task_status_from_redmine'.
    :return: 
    """
    key = 'get_task_status_from_redmine'
    sql_str = sql_mapping.SQL_MAPPING[key]
    param_value = [task_id]
    # print(sql_str,param_value,schema)
    df = Mysql_DB(schema).do_sql_query(sql_str, param_value)
    if not df.empty:
        return df['name'].values[0]
    else:
        return None


def extract_gittag_from_redmine(df, schema):
    """
    from query df, extract the gittags record list
    :param column: the operation column name. here is value
    :param df:qeury df from database.
    :return: List[gittags]. return the gittags record list
    """
    # get the value list from df
    column = sql_mapping.COLUMN_MAPPING[schema]
    try:

        str = df[column].values[0]
        record_list = re.split('\r|\r\n|\n|：|:|,| ', str)
        # build regex compiler patten. search ld... patten
        re_str = r'^(ld)\w*'
        job_pattern = re.compile(re_str)
        git_tags_list = []
        # from query result,select matched gittags adding to list
        for git_tag in record_list:
            match = job_pattern.match(git_tag)
            if match:
                git_tags_list.append(git_tag)
        # return git tags list
        return git_tags_list
    # if IndexError,there's no result from query. return empty list
    except IndexError:
        return []


def extract_gittag_from_zeus(df, schema):
    """
    from query df, extract the gittags record list
    the difference from extract_gittag_from_redmine is the record is in 'qa_version' column
     by sql_mapping.COLUMN_MAPPING[schema].

    :param column: the operation column name. here is value
    :param df:qeury df from database.
    :return: List[gittags]. return the gittags record list
    """
    # get the value list from df

    try:
        column = sql_mapping.COLUMN_MAPPING[schema]
        record_list = df[column].values
        git_tags_list = record_list
        return git_tags_list
    except Exception as e:
        logger.error(module_name, sys._getframe().f_code.co_name, EnhanceUtills.traceback_printer(),
                     system_id)


def get_gittags_from_redmine(input_task_id, schema='redmine'):
    """
    get_gittags_from_redmine
    :param input_task_id: must be int
    :param schema: str, redmine default
    :return:git_tags_list
    """
    # query value text from db
    sub_df = get_info_from_db(schema, input_task_id, sql_mapper=schema)
    # process and return git tags list
    git_tags_list = extract_gittag_from_redmine(sub_df, schema)
    return git_tags_list


def get_gittags_from_zeus(input_task_id: int, schema: str = 'zeus'):
    """
    get_gittags_from_zeus
    :param input_task_id: must be int
    :param schema: str, zeus default
    :return:git_tags_list
    """
    # query value text from db
    sub_df = get_info_from_db(schema=schema, task_id=input_task_id, sql_mapper=schema)
    sub_df = sub_df.sort_values(['release_count'], ascending=False).groupby(['sys_id']).nth(0)
    # process and return git tags list
    git_tags_list = extract_gittag_from_zeus(sub_df, schema)
    return git_tags_list


def git_tag_build(task_id: str):
    """
    input the task_id, return the git tags from redmine, flag need_to_build and flag multi_build.
    if "need_to_build" is True, the git tag need to be build.
    if "multi_build" is True, the git tag is a multi build.

    :param task_id: the task_number.
    :return:df_git_tag: pandas.Dataframe. column:{"index","git_tag","need_to_build","multi_build"}
    """
    zeus_gittag_list = get_gittags_from_zeus(task_id, 'zeus')
    redmine_gittag_list = get_gittags_from_redmine(task_id, 'redmine')
    # the dict to represent if need to build flag
    dict_to_build = {}
    # the dict to represent if the git_tag is a multi build flag
    dict_multi_build = {}
    # check the zeus list. if empty, the git_tags in redmine are all 1st time,need to build.
    if len(zeus_gittag_list) == 0:
        dict_redmine = get_dict_from_gittags(redmine_gittag_list)

        for key in dict_redmine:
            dict_to_build[key] = True
            dict_multi_build[key] = True
    else:
        # compare each key(sys_id,e.g, ld067) and value(git_tag, e.g,ld067_mes_build_No.29171_20200616.5_T)
        # in dict_zeus and dict_redmine.
        dict_zeus = get_dict_from_gittags(zeus_gittag_list)
        dict_redmine = get_dict_from_gittags(redmine_gittag_list)
        # enumerate the redmine dict
        for key, value in dict_redmine.items():
            # if the sys_id exists in zeus record.
            if key in dict_zeus:
                # the redmine git_tag doesnt match zeus' git_tag, means it's NEED to build, and it's a multi build
                if value != dict_zeus[key]:
                    dict_to_build[key] = True
                    dict_multi_build[key] = True
                # the redmine git_tag  matches zeus' git_tag, means it's NOT NEED to build, and it's NOT a multi build
                else:
                    dict_to_build[key] = False
                    dict_multi_build[key] = False
            # if the sys_id does not exist in zeus record
            # the redmine git_tag  is NEED to build, and it's NOT a multi build
            else:
                dict_to_build[key] = True
                dict_multi_build[key] = False
    # use dict_redmine as result
    s1 = pd.Series(dict_redmine, name='gittag')
    s2 = pd.Series(dict_to_build, name='need_to_build')
    s3 = pd.Series(dict_multi_build, name='is_multi_build')
    df_git_tag = pd.concat([s1, s2, s3], axis=1)
    df_git_tag.reset_index(inplace=True)
    return df_git_tag


def get_dict_from_gittags(gittags: list) -> dict:
    """
    from gittags, extract sys_id [ldXXX]to be key, whole gitag version to be value.

    :param gittags:
    :return: dict_tags:dict
    """
    dict_tags = {}
    # enumerate the list
    for i, val in enumerate(gittags):
        # search the LD/ldXXX as prefix string,
        re_str = r'[lL][dD](\d)*'
        pattern = re.compile(re_str)
        # return a match
        list_str = pattern.search(val)
        # span() return the (start,end) index tuple for the match
        start, end = (list_str.span())
        if list_str is not None:
            # key is the match substring, val is the whole string.
            key, value = val[start:end], val
            dict_tags[key] = value
    return dict_tags


def get_release_versions_to_build(task_id: int) -> list:
    """
    get the release versions info from zeus. Only select the most recent release pre info.

    :param task_id: the task id.
    :return: List<Str> return the List of Str, represent the strings of the pre-env released info.
            e,g,['ld043_online_No.28666_20200312.1_pre','ld227_fpa_No.28666_20200312.1_pre'..]
    """
    # select release_version,release_count from release_record where task_id = '#29332'  AND  release_env = 'pre'
    # 首先，查询出全部的最新 release_count 的pre记录
    # 2nd, 根据每一条记录的 env=prod, qa_version=记录.qa_version 查找 prod记录。
    # 如果返回记录不为空，则此记录已经发布。
    # 如果返回记录为空，则此pre记录未发布，需要发布生产，加入返回结果集合。
    # 最后返回全部结果集合
    try:
        sql_mapper: str = "cmdb_get_release_versions"
        sql_str = sql_mapping.SQL_MAPPING[sql_mapper]
        # the param is task_id,task_id since need 2 task param in sql.
        param_value = [task_id]
        list_release_versions = []
        schema = "zeus"
        df = Mysql_DB(schema).do_sql_query(sql_str, param_value)
        # 首先，查询出全部的最新 release_count 的pre记录，总数量=task中系统数
        df_latest_pre = df.loc[(df['release_env'] == 'pre')].sort_values(['release_count'], ascending=False).groupby(
            ['sys_id']).nth(0)
        df_prod = df.loc[df['release_env'] == 'prod']
        # 其次, 根据每一条记录的 env=prod, qa_version=记录.qa_version 查找 prod记录。
        for index, row in df_latest_pre.iterrows():
            pre_qa_version = row['qa_version']
            result = df_prod.loc[df_prod['qa_version'] == pre_qa_version]
            # 如果prod的qa_version与pre一阵,说明已发布,pass
            if not result.empty:
                pass
            # 如果prod的qa_version与pre不一阵,说明未发布,此条release_version加入结果集
            else:
                list_release_versions.append(row['release_version'])
        # end loop
        # return result list.
        return list_release_versions
    except Exception as e:
        logger.error(module_name, sys._getframe().f_code.co_name, EnhanceUtills.traceback_printer(),
                     system_id)
        return list_release_versions


def get_release_version_to_deploy(task_id: int, env="pre") -> pd.DataFrame:
    """
    get the release versions which are ready to deploy on pre/prod from prod jenkins.
    Only select the unreleased, most recent release versions.

    :param task_id: the task id.
    :param env: the environment. including "pre" and "prod"
    :return: DataFrame. return the df contains deploy related info or an empty df.
    """
    list_if_to_deploy = []
    df_latest_pre_build = pd.DataFrame()
    try:
        if env == "pre":
            sql_mapper: str = "get_release_versions_to_deploy_on_pre"
        if env == "prod":
            sql_mapper: str = "get_release_versions_to_deploy_on_prod"
        sql_str = sql_mapping.SQL_MAPPING[sql_mapper]
        param_value = [task_id]
        schema = "zeus"
        df = Mysql_DB(schema).do_sql_query(sql_str, param_value)
        # 首先，查询出全部的最新 当前环境 的 build记录，总数量=task中系统数
        df_latest_pre_build = df.loc[(df['release_env'] == env)].sort_values(['create_time'],
                                                                             ascending=False).groupby(
            ['sys_id']).nth(0)
        # 查询出全部的 当前环境 最新的deploy_count 非空发布记录
        df_latest_pre_deploy = df.loc[(df['release_env'] == env) & (df['deploy_count'].notnull())].sort_values(
            ['create_time'], ascending=False).groupby(
            ['sys_id']).nth(0)
        # 其次, 根据每一条记录的 env=prod, qa_version=记录.qa_version 查找 prod记录。
        for index, row in df_latest_pre_build.iterrows():
            build_version = row['release_version']
            result = df_latest_pre_deploy.loc[df_latest_pre_deploy['release_version'] == build_version]
            # 如果prod的qa_version与pre一阵,说明已发布,此记录记为false
            if not result.empty:
                list_if_to_deploy.append(False)
            # 如果prod的qa_version与pre不一阵,说明未发布,此记录几位true
            else:
                list_if_to_deploy.append(True)
        # end loop
        # return result list.
        df_latest_pre_build['need_to_deploy'] = list_if_to_deploy
        # add executable job name list

        df_latest_pre_build.reset_index(inplace=True)
        return df_latest_pre_build
    except Exception as e:
        logger.error(module_name, sys._getframe().f_code.co_name, EnhanceUtills.traceback_printer(),
                     system_id)
        return df_latest_pre_build


if __name__ == "__main__":
    sub_df = get_status_from_redmine(2)
    print(sub_df)
    input_task_id = 29732
    r_tag_list = (get_gittags_from_redmine(input_task_id, 'redmine'))
    z_tag_list = (get_gittags_from_zeus(input_task_id, 'zeus'))
    df_gittag = (git_tag_build(input_task_id))
    print(df_gittag)
    # sub_df = get_info_from_db(schema='zeus', task_id=input_task_id, sql_mapper='zeus')
    # print(sub_df)
    # result_df = sub_df.sort_values(['release_count'], ascending=False).groupby(['sys_id']).nth(0)
    # print(result_df)

    df_release_versions = get_release_versions_to_build(input_task_id)
    print(df_release_versions)
    df_release_versions = get_release_version_to_deploy(input_task_id, env="prod")
    print(df_release_versions)
    # dict_tag = get_dict_from_gittags(r_tag_list)
    # print(dict_tag)
